//
// Created by martin on 2/15/22.
//

#ifndef MUDUO_INETADDRESS_H
#define MUDUO_INETADDRESS_H

#include "muduo/base/copyable.h"
#include "muduo/base/StringPiece.h"

#include <netinet/in.h>

namespace muduo
{
namespace net
{
namespace sockets
{
const struct sockaddr* sockaddr_cast(const struct sockaddr_in6* addr);
} // namespace sockets

/**
 * sockaddr_in包装类.
 *
 * POD(Plain Old Data) 接口类, 便于Ｃ++和Ｃ之间数据类型的兼容性.
 */
class InetAddress : public muduo::copyable
{
public:
    /**
     * 用给定端口号构造一个端(ip + port).
     * 常用于TcpServer, 监听本地地址.
     */
    explicit InetAddress(uint16_t portArg = 0, bool loopbackOnly = false, bool ipv6 = false);

    /**
     * 构建一个InetAddress对象, 用于将一个port + 字符串形式的ip地址转化为InetAddress对象.
     */
    InetAddress(StringArg ip, uint16_t portArg, bool ipv6 = false);

    /* 根据sockaddr_in构造InetAddress对象 */
    explicit InetAddress(const struct sockaddr_in& addr)
            : addr_(addr)
    { }

    /* 根据sockaddr_in6构造InetAddress对象 */
    explicit InetAddress(const struct sockaddr_in6& addr)
            : addr6_(addr)
    { }

    /* 获取协议族类型 */
    sa_family_t family() const { return addr_.sin_family; }
    /* 获取ip地址字符串形式.
     * 对于ipv4, 为点分十进制; 对于ipv6, 为冒号十六进制. */
    string toIp() const;
    /* 获取ip地址+port字符串形式. */
    string toIpPort() const;
    /* 获取端口号(主机端) */
    uint16_t port() const;

    // default copy/assignment are Okay

    const struct sockaddr* getSockAddr() const { return sockets::sockaddr_cast(&addr6_); }
    void setSockAddrInet6(const struct sockaddr_in6& addr6) { addr6_ = addr6; }

    /* 获取ipv4地址网络端(大端) */
    uint32_t ipv4NetEndian() const;
    /* 获取端口号网络端(大端) */
    uint16_t portNetEndian() const { return addr_.sin_port; }

    /**
     * 将hostname转换为IP地址, 存放到result, 而不改变port或sin_family.
     * 线程安全.
     */
    static bool resolve(StringArg hostname, InetAddress* result);

    /* 设置IPv6 ScopeID(域ID) */
    void setScopedId(uint32_t scope_id);

private:
    union
    {
        struct sockaddr_in addr_;
        struct sockaddr_in6 addr6_;
    };
};

} // namespace net
} // namespace muduo

#endif //MUDUO_INETADDRESS_H
